
#include "bsp.h"
#include "font8x8_basic.h"
#include "font5_7.h"

#define TAG "SSD1306"
#define tag "SSD1306"


#define CONFIG_MOSI_GPIO          6
#define CONFIG_SCLK_GPIO          7
#define CONFIG_CS_GPIO              5
#define CONFIG_DC_GPIO              4
#define CONFIG_RESET_GPIO          -1

#define LCD_HOST  1  //SPI2_HOST

#define CONFIG_OFFSETX 1


static const int SPI_Command_Mode = 0;
static const int SPI_Data_Mode = 1;
static const int SPI_Frequency = 1000000;


SSD1306_t dev;

////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
/* 12864 OLED的显存镜像，占用1K字节. 共8行，每行128像素 */
static uint8_t s_ucGRAM[8][128];

/* 为了避免刷屏拉幕感太强，引入刷屏标志。
0 表示显示函数只改写缓冲区，不写屏。1 表示直接写屏（同时写缓冲区） */
static uint8_t s_ucUpdateEn = 1;  



//用PCtoLCD2002取模软件取模，宋体  设置12*12高宽，阴码，逐行式顺向
const unsigned char uichfont_1212[][24]={


//0:制作人姚伟民
{0x10,0x20,0x54,0x20,0x7E,0xA0,0x90,0xA0,0xFE,0xA0,0x10,0xA0,0x7E,0xA0,0x52,0xA0,0x52,0x20,0x56,0x20,0x10,0xE0,0x00,0x00},/*"制",0*/
{0x12,0x00,0x12,0x00,0x27,0xE0,0x6A,0x00,0xB2,0x00,0x23,0xC0,0x22,0x00,0x22,0x00,0x23,0xE0,0x22,0x00,0x22,0x00,0x00,0x00},/*"作",1*/
{0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x0A,0x00,0x0A,0x00,0x11,0x00,0x11,0x00,0x20,0x80,0xC0,0x60,0x00,0x00},/*"人",2*/
{0x22,0x80,0x22,0x80,0xFA,0xA0,0x56,0xC0,0x52,0x80,0x52,0x80,0x96,0xC0,0xEA,0xA0,0x22,0x80,0x54,0xA0,0x88,0xE0,0x00,0x00},/*"姚",3*/
{0x22,0x00,0x3F,0xE0,0x22,0x00,0x6F,0xC0,0xA2,0x00,0x3F,0xE0,0x22,0x20,0x22,0x20,0x22,0x20,0x22,0xC0,0x22,0x00,0x00,0x00},/*"伟",4*/
{0x7F,0xC0,0x40,0x40,0x40,0x40,0x7F,0xC0,0x44,0x00,0x7F,0xE0,0x44,0x00,0x42,0x00,0x4A,0x20,0x51,0x20,0x60,0xE0,0x00,0x00},/*"民",5*/
//6：欢迎使用
{0x02,0x00,0xFA,0x00,0x13,0xE0,0x94,0x20,0x55,0x40,0x21,0x00,0x21,0x00,0x52,0x80,0x4A,0x80,0x84,0x40,0x18,0x20,0x00,0x00},/*"欢",0*/
{0x42,0x00,0x2D,0xE0,0x09,0x20,0xC9,0x20,0x49,0x20,0x49,0x20,0x4F,0x20,0x49,0x60,0x41,0x00,0xB0,0x00,0x8F,0xE0,0x00,0x00},/*"迎",1*/
{0x11,0x00,0x2F,0xE0,0x21,0x00,0x6F,0xE0,0xA9,0x20,0x29,0x20,0x2F,0xE0,0x25,0x00,0x22,0x00,0x25,0x00,0x38,0xE0,0x00,0x00},/*"使",2*/
{0x7F,0xC0,0x44,0x40,0x44,0x40,0x7F,0xC0,0x44,0x40,0x44,0x40,0x7F,0xC0,0x44,0x40,0x44,0x40,0x84,0x40,0x85,0xC0,0x00,0x00},/*"用",3*/
//10：温湿度星期
{0x8F,0xC0,0x48,0x40,0x0F,0xC0,0x88,0x40,0x4F,0xC0,0x40,0x00,0x5F,0xC0,0x95,0x40,0x95,0x40,0x95,0x40,0xBF,0xE0,0x00,0x00},/*"温",0*/
{0x4F,0xC0,0x28,0x40,0x0F,0xC0,0xA8,0x40,0x6F,0xC0,0x45,0x00,0x55,0x20,0xD5,0x40,0x4D,0x80,0x45,0x00,0x7F,0xE0,0x00,0x00},/*"湿",1*/
{0x02,0x00,0x7F,0xE0,0x48,0x80,0x7F,0xE0,0x48,0x80,0x4F,0x80,0x40,0x00,0x5F,0x80,0x45,0x00,0x87,0x00,0xB8,0xE0,0x00,0x00},/*"度",2*/
{0x3F,0xC0,0x20,0x40,0x3F,0xC0,0x20,0x40,0x3F,0xC0,0x24,0x00,0x3F,0xC0,0x44,0x00,0xBF,0xC0,0x04,0x00,0xFF,0xE0,0x00,0x00},/*"星",3*/
{0x49,0xE0,0xFD,0x20,0x49,0x20,0x79,0xE0,0x49,0x20,0x79,0x20,0x49,0xE0,0xFD,0x20,0x29,0x20,0x45,0x20,0x82,0x60,0x00,0x00},/*"期",4*/
//15：一二三四五六日
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"一",0*/
{0x00,0x00,0x00,0x80,0x7F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xE0,0x00,0x00,0x00,0x00},/*"二",1*/
{0x00,0x80,0x7F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0xFF,0xE0,0x00,0x00},/*"三",2*/
{0x7F,0xE0,0x49,0x20,0x49,0x20,0x49,0x20,0x49,0x20,0x49,0x20,0x51,0x20,0x61,0xE0,0x40,0x20,0x7F,0xE0,0x40,0x20,0x00,0x00},/*"四",3*/
{0x7F,0xC0,0x08,0x00,0x08,0x00,0x08,0x00,0x7F,0x80,0x08,0x80,0x08,0x80,0x10,0x80,0x10,0x80,0x10,0x80,0xFF,0xE0,0x00,0x00},/*"五",4*/
{0x08,0x00,0x04,0x00,0x04,0x00,0xFF,0xE0,0x00,0x00,0x12,0x00,0x11,0x00,0x20,0x80,0x20,0x80,0x40,0x40,0x80,0x40,0x00,0x00},/*"六",5*/
{0x3F,0xC0,0x20,0x40,0x20,0x40,0x20,0x40,0x3F,0xC0,0x20,0x40,0x20,0x40,0x20,0x40,0x20,0x40,0x3F,0xC0,0x20,0x40,0x00,0x00},/*"日",6*/

//22 主菜单
{0x08,0x00,0x04,0x40,0xFF,0xE0,0x04,0x00,0x04,0x00,0x04,0x00,0x7F,0xC0,0x04,0x00,0x04,0x00,0x04,0x00,0xFF,0xE0,0x00,0x00},/*"主",0*/
{0x12,0x00,0xFF,0xE0,0x12,0x00,0x7F,0xC0,0x44,0x80,0x24,0x80,0x15,0x00,0xFF,0xE0,0x15,0x00,0x24,0x80,0xC4,0x60,0x00,0x00},/*"菜",1*/
{0x11,0x00,0x0A,0x00,0x3F,0xC0,0x24,0x40,0x3F,0xC0,0x24,0x40,0x3F,0xC0,0x04,0x00,0xFF,0xE0,0x04,0x00,0x04,0x00,0x00,0x00},/*"单",2*/
//25 模式层列
{0x2F,0xE0,0x22,0x80,0xF7,0xC0,0x24,0x40,0x67,0xC0,0x74,0x40,0xA7,0xC0,0xA1,0x00,0x2F,0xE0,0x22,0x80,0x2C,0x60,0x00,0x00},/*"模",0*/
{0x02,0x80,0x02,0x40,0xFF,0xE0,0x02,0x00,0x02,0x00,0xFE,0x00,0x12,0x00,0x11,0x00,0x11,0x20,0x1C,0xA0,0xE0,0x60,0x00,0x00},/*"式",1*/
{0x7F,0xC0,0x40,0x40,0x7F,0xC0,0x40,0x00,0x5F,0xC0,0x40,0x00,0x7F,0xE0,0x44,0x00,0x45,0x00,0x88,0x80,0x9F,0xC0,0x00,0x00},/*"层",2*/
{0x04,0x20,0xFE,0x20,0x21,0x20,0x3D,0x20,0x25,0x20,0x65,0x20,0x99,0x20,0x09,0x20,0x11,0x20,0x20,0x20,0xC1,0xE0,0x00,0x00},/*"列",3*/
//29 设置卡
{0x47,0x80,0x24,0x80,0x04,0x80,0x04,0xE0,0xE8,0x00,0x37,0xC0,0x24,0x40,0x22,0x80,0x31,0x00,0x22,0x80,0x1C,0x60,0x00,0x00},/*"设",21*/
{0x7F,0xC0,0x4A,0x40,0x7F,0xC0,0x04,0x00,0xFF,0xE0,0x20,0x80,0x3F,0x80,0x20,0x80,0x3F,0x80,0x20,0x80,0xFF,0xE0,0x00,0x00},/*"置",22*/
{0x08,0x00,0x0F,0xC0,0x08,0x00,0x08,0x00,0xFF,0xE0,0x08,0x00,0x0E,0x00,0x09,0x80,0x08,0x40,0x08,0x00,0x08,0x00,0x00,0x00},/*"卡",20*/
//32 组网请求
{0x20,0x00,0x27,0xC0,0x44,0x40,0x94,0x40,0xE7,0xC0,0x24,0x40,0x44,0x40,0xF7,0xC0,0x04,0x40,0x34,0x40,0xC4,0x40,0x0F,0xE0},/*"组",0*/
{0xFF,0xE0,0x80,0x20,0x80,0x20,0xC4,0x60,0xAA,0xA0,0x91,0x20,0x91,0x20,0xAA,0xA0,0xC4,0x60,0x80,0x20,0x80,0x20,0x80,0xE0},/*"网",1*/
{0x82,0x00,0x5F,0xE0,0x02,0x00,0x0F,0xC0,0xC2,0x00,0x5F,0xE0,0x48,0x40,0x4F,0xC0,0x48,0x40,0x4F,0xC0,0x68,0x40,0x48,0xC0},/*"请",2*/
{0x04,0x80,0x04,0x40,0xFF,0xE0,0x04,0x00,0x46,0x40,0x26,0x80,0x0D,0x00,0x15,0x00,0x24,0x80,0xC4,0x40,0x04,0x20,0x0C,0x00},/*"求",3*/

//36 可以编号
{0x00,0x00,0xFF,0xE0,0x00,0x40,0x00,0x40,0x7E,0x40,0x42,0x40,0x42,0x40,0x42,0x40,0x7E,0x40,0x40,0x40,0x00,0x40,0x01,0xC0},/*"可",0*/
{0x00,0x80,0x48,0x80,0x44,0x80,0x44,0x80,0x40,0x80,0x40,0x80,0x48,0x80,0x51,0x00,0x61,0x00,0x42,0x80,0x0C,0x40,0x30,0x20},/*"以",1*/
{0x41,0x00,0x4F,0xE0,0x88,0x20,0xAF,0xE0,0xC8,0x00,0x4F,0xE0,0x8A,0xA0,0xDA,0xA0,0x0F,0xE0,0x2A,0xA0,0xCA,0xA0,0x08,0x60},/*"编",2*/
{0x3F,0x80,0x20,0x80,0x20,0x80,0x3F,0x80,0x00,0x00,0xFF,0xE0,0x10,0x00,0x20,0x00,0x3F,0xC0,0x00,0x40,0x00,0x40,0x01,0x80},/*"号",3*/

//40 次数行
{0x04,0x00,0x84,0x00,0x47,0xE0,0x08,0x20,0x0A,0x40,0x12,0x00,0x02,0x00,0x25,0x00,0x45,0x00,0x88,0x80,0x10,0x40,0x20,0x20},/*"次",0*/
{0x11,0x00,0x55,0x00,0x11,0x00,0xFD,0xE0,0x32,0x40,0x59,0x40,0x95,0x40,0x21,0x40,0xF9,0x40,0x48,0x80,0x31,0x40,0xCA,0x20},/*"数",1*/
{0x10,0x00,0x27,0xC0,0x40,0x00,0x90,0x00,0x2F,0xE0,0x60,0x80,0xA0,0x80,0x20,0x80,0x20,0x80,0x20,0x80,0x20,0x80,0x23,0x80},/*"行",2*/

//43 接近式界面空空
{0x22,0x00,0x21,0x00,0x2F,0xE0,0xF4,0x40,0x22,0x80,0x2F,0xE0,0x31,0x00,0xEF,0xE0,0x22,0x40,0x26,0x40,0x21,0x80,0x6E,0x60},/*"接",0*/
{0x40,0xC0,0x27,0x00,0x04,0x00,0x04,0x00,0xE7,0xE0,0x24,0x80,0x24,0x80,0x24,0x80,0x24,0x80,0x28,0x80,0x50,0x00,0x8F,0xE0},/*"近",1*/
{0x01,0x40,0x01,0x20,0x01,0x00,0xFF,0xE0,0x01,0x00,0x01,0x00,0x7D,0x00,0x11,0x00,0x10,0x80,0x10,0xA0,0x1E,0x60,0xE0,0x20},/*"式",2*/
{0x7F,0xC0,0x44,0x40,0x7F,0xC0,0x44,0x40,0x7F,0xC0,0x04,0x00,0x1B,0x00,0xE0,0xE0,0x11,0x00,0x11,0x00,0x21,0x00,0x41,0x00},/*"界",3*/
{0x00,0x00,0xFF,0xE0,0x04,0x00,0x08,0x00,0x7F,0xE0,0x49,0x20,0x4F,0x20,0x49,0x20,0x4F,0x20,0x49,0x20,0x7F,0xE0,0x40,0x20},/*"面",4*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"  ",5*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"  ",6*/

//50 注册成功失
{0x04,0x00,0x82,0x00,0x40,0x00,0x1F,0xC0,0x02,0x00,0x82,0x00,0x42,0x00,0x1F,0xC0,0x02,0x00,0x42,0x00,0x82,0x00,0x3F,0xE0},/*"注",0*/
{0x00,0x00,0x7B,0xC0,0x4A,0x40,0x4A,0x40,0x4A,0x40,0x4A,0x40,0xFF,0xE0,0x4A,0x40,0x4A,0x40,0x4A,0x40,0x4A,0x40,0x9C,0xC0},/*"册",1*/
{0x02,0x80,0x02,0x40,0x7F,0xE0,0x42,0x00,0x42,0x00,0x7A,0x40,0x4A,0x40,0x4A,0x80,0x49,0x20,0x5A,0xA0,0x44,0x60,0x88,0x20},/*"成",2*/
{0x02,0x00,0x02,0x00,0xFA,0x00,0x27,0xE0,0x22,0x20,0x22,0x20,0x22,0x20,0x22,0x20,0x3C,0x20,0xC4,0x20,0x08,0x20,0x10,0xC0},/*"功",3*/
{0x04,0x00,0x24,0x00,0x24,0x00,0x3F,0x80,0x44,0x00,0x84,0x00,0x04,0x00,0xFF,0xE0,0x0A,0x00,0x11,0x00,0x20,0x80,0xC0,0x60},/*"失",4*/

//55 探测距离
{0x20,0x00,0x2F,0xE0,0x28,0x20,0xF2,0x80,0x24,0x40,0x21,0x00,0x2F,0xE0,0x31,0x00,0xE3,0x80,0x25,0x40,0x29,0x20,0x61,0x00},/*"探",0*/
{0x00,0x20,0xBE,0x20,0x62,0xA0,0x2A,0xA0,0x2A,0xA0,0xAA,0xA0,0x6A,0xA0,0x2A,0xA0,0x2A,0xA0,0x48,0x20,0x94,0x20,0x22,0x60},/*"测",1*/
{0x00,0x00,0x7B,0xE0,0x4A,0x00,0x4A,0x00,0x7B,0xE0,0x12,0x20,0x12,0x20,0x5A,0x20,0x53,0xE0,0x52,0x00,0x5A,0x00,0xE3,0xE0},/*"距",2*/
{0x04,0x00,0xFF,0xE0,0x11,0x00,0x4E,0x40,0x51,0x40,0x7F,0xC0,0x04,0x00,0xFF,0xE0,0x88,0x20,0x92,0x20,0xBF,0x20,0x81,0x60},/*"离",3*/

//59 参数查看
{0x10,0x00,0x20,0x80,0x7F,0xC0,0x08,0x00,0xFF,0xE0,0x22,0x80,0x4C,0x40,0xB1,0x20,0x06,0x00,0x78,0x40,0x03,0x80,0x7C,0x00},/*"参",0*/
{0x11,0x00,0x55,0x00,0x11,0x00,0xFD,0xE0,0x32,0x40,0x59,0x40,0x95,0x40,0x21,0x40,0xF9,0x40,0x48,0x80,0x31,0x40,0xCA,0x20},/*"数",1*/
{0x04,0x00,0xFF,0xE0,0x15,0x00,0x24,0x80,0xC4,0x60,0x3F,0x80,0x20,0x80,0x3F,0x80,0x20,0x80,0x3F,0x80,0x00,0x00,0xFF,0xE0},/*"查",2*/
{0x03,0xC0,0x7C,0x00,0x04,0x00,0x7F,0xC0,0x08,0x00,0xFF,0xE0,0x20,0x40,0x7F,0xC0,0xA0,0x40,0x3F,0xC0,0x20,0x40,0x3F,0xC0},/*"看",3*/



};


/*
*********************************************************************************************************
*	函 数 名: OLED_BufToPanel
*	功能说明: 将缓冲区中的点阵数据写入面板
*	形    参:  无
*	返 回 值: 无
*********************************************************************************************************
*/
static void OLED_BufToPanel(void)
{
	uint8_t i,j;

	for (i = 0 ; i< 8; i++)
	{
		for (j = 0 ; j < 128; j++)
		{
			ssd1306_display_image(&dev,i,j,&s_ucGRAM[i][j],1);
		}
	}
}

/*
*********************************************************************************************************
*	函 数 名: OLED_StartDraw
*	功能说明: 开始绘图。以后绘图函数只改写缓冲区，不改写面板显存
*	形    参:  无
*	返 回 值: 无
*********************************************************************************************************
*/
void OLED_StartDraw(void)
{
	s_ucUpdateEn = 0;
}

/*
*********************************************************************************************************
*	函 数 名: OLED_EndDraw
*	功能说明: 结束绘图。缓冲区的数据刷新到面板显存。 OLED_StartDraw() 和 OLED_EndDraw() 必须成对使用
*	形    参:  无
*	返 回 值: 无
*********************************************************************************************************
*/
void OLED_EndDraw(void)
{
	s_ucUpdateEn = 1;
	OLED_BufToPanel();
}

/*
*********************************************************************************************************
*	函 数 名: OLED_ClrScr
*	功能说明: 清屏
*	形    参:  _ucMode : 0 表示全黑； 0xFF表示全亮
*	返 回 值: 无
*********************************************************************************************************
*/
void OLED_ClrScr(uint8_t _ucMode)
{
	uint8_t i,j;

	for (i = 0 ; i < 8; i++)
	{
		for (j = 0 ; j < 128; j++)
		{
			s_ucGRAM[i][j] = _ucMode;
		}
	}

	if (s_ucUpdateEn == 1)
	{
		OLED_BufToPanel();
	}
}

/*
*********************************************************************************************************
*	函 数 名: OLED_PutPixel
*	功能说明: 画1个像素
*	形    参:
*			_usX,_usY : 像素坐标
*			_ucColor  ：像素颜色
*	返 回 值: 无
*********************************************************************************************************
*/
void OLED_PutPixel(uint16_t _usX, uint16_t _usY, uint8_t _ucColor)
{
	uint8_t ucValue;
	uint8_t ucPageAddr;
	uint8_t ucColAddr;

	///const uint8_t aOrTab[8]  = {0x01, 0x02, 0x04, 0x08,0x10,0x20,0x40,0x80};
	///const uint8_t aAndTab[8] = {0xFE, 0xFD, 0xFB, 0xF7,0xEF,0xDF,0xBF,0x7F};

	const uint8_t aOrTab[8]  = {0x80, 0x40, 0x20, 0x10,0x08,0x04,0x02,0x01};
	const uint8_t aAndTab[8] = {0x7F, 0xBF, 0xDF, 0xEF,0xF7,0xFB,0xFD,0xFE};

	ucPageAddr = _usY / 8;
	ucColAddr = _usX;

	ucValue = s_ucGRAM[ucPageAddr][ucColAddr];
	if (_ucColor == 0)
	{
		ucValue &= aAndTab[_usY % 8];
	}
	else
	{
		ucValue |= aOrTab[_usY % 8];
	}
	s_ucGRAM[ucPageAddr][ucColAddr] = ucValue;

	if (s_ucUpdateEn == 1)
	{
		
	}
}

/*
*********************************************************************************************************
*	函 数 名: OLED_DrawLine
*	功能说明: 采用 Bresenham 算法，在2点间画一条直线。
*	形    参:
*			_usX1, _usY1 ：起始点坐标
*			_usX2, _usY2 ：终止点Y坐标
*			_ucColor     ：颜色
*	返 回 值: 无
*********************************************************************************************************
*/
void OLED_DrawLine(uint16_t _usX1 , uint16_t _usY1 , uint16_t _usX2 , uint16_t _usY2 , uint8_t _ucColor)
{
	int32_t dx , dy ;
	int32_t tx , ty ;
	int32_t inc1 , inc2 ;
	int32_t d , iTag ;
	int32_t x , y ;

	/* 采用 Bresenham 算法，在2点间画一条直线 */

	OLED_PutPixel(_usX1 , _usY1 , _ucColor);

	/* 如果两点重合，结束后面的动作。*/
	if ( _usX1 == _usX2 && _usY1 == _usY2 )
	{
		return;
	}

	iTag = 0 ;
	/* dx = abs ( _usX2 - _usX1 ); */
	if (_usX2 >= _usX1)
	{
		dx = _usX2 - _usX1;
	}
	else
	{
		dx = _usX1 - _usX2;
	}

	/* dy = abs ( _usY2 - _usY1 ); */
	if (_usY2 >= _usY1)
	{
		dy = _usY2 - _usY1;
	}
	else
	{
		dy = _usY1 - _usY2;
	}

	if ( dx < dy )   /*如果dy为计长方向，则交换纵横坐标。*/
	{
		uint16_t temp;

		iTag = 1 ;
		temp = _usX1; _usX1 = _usY1; _usY1 = temp;
		temp = _usX2; _usX2 = _usY2; _usY2 = temp;
		temp = dx; dx = dy; dy = temp;
	}
	tx = _usX2 > _usX1 ? 1 : -1 ;    /* 确定是增1还是减1 */
	ty = _usY2 > _usY1 ? 1 : -1 ;
	x = _usX1 ;
	y = _usY1 ;
	inc1 = 2 * dy ;
	inc2 = 2 * ( dy - dx );
	d = inc1 - dx ;
	while ( x != _usX2 )     /* 循环画点 */
	{
		if ( d < 0 )
		{
			d += inc1 ;
		}
		else
		{
			y += ty ;
			d += inc2 ;
		}
		if ( iTag )
		{
			OLED_PutPixel ( y , x , _ucColor) ;
		}
		else
		{
			OLED_PutPixel ( x , y , _ucColor) ;
		}
		x += tx ;
	}
}


//5*7字体
//row==(0,64)   col==(0,128)
void Lcd_String_Small(char* pStr, u8 row, u8 col, u8 bIsReverse)
{

	if(bIsReverse)
	{
		GUI_SetColor(0,1);
		GUI_PutString(col, row, pStr);
		GUI_SetColor(1,0);
	}
	else
	{	
		GUI_PutString(col, row, pStr);
	}
}

//row==(0,63)   col==(0,127)
void Lcd_Decimal_Small(int nValue, u8 row, u8 col, u8 bIsReverse, u8 nZeroPadding)
{
	int i, nPadding;
	char str[32], str2[32];
	sprintf(str2, "%d", nValue);
	nPadding = nZeroPadding - strlen(str2);
	if (nPadding > 0)
	{
		for (i=0; i<nPadding; i++)
			str[i] = '0';
		str[nPadding] = 0;
	}
	else
	{
		str[0] = 0;
	}
	strcat(str, str2);
	Lcd_String_Small(str, row, col, bIsReverse);
}


//行0~4
//列0~9
//address,汉字编码存储位置
//一次显示几个汉字
void Lcd_HZ_1212(u8 address,u8 row,u8 col,u8 num)
{
	 int i;
	 if(row>4 || col>9)
	 {
		return;
	 }
	 for(i=0;i<num;i++)
	 {
		 GUI_PutHZ(4+col*GUI_FONT_SIZE+GUI_FONT_SIZE*i, 2+row*GUI_FONT_SIZE, (uint8 *)&uichfont_1212[address+i][0], GUI_FONT_SIZE, GUI_FONT_SIZE);
	 }
}

//此函数供菜单专用的
//行0~3
//列0~9
//address,汉字编码存储位置
//一次显示几个汉字
void Lcd_HZ_1212_CD(u8 address,u8 row,u8 col,u8 num)
{
	 int i; 
	 if(row>3 || col>9)
	 {
		return;
	 }
	 for(i=0;i<num;i++)
	 {
		 GUI_PutHZ(4+col*GUI_FONT_SIZE+GUI_FONT_SIZE*i, 1+row*GUI_FONT_SIZE+row*2, (uint8 *)&uichfont_1212[address+i][0], GUI_FONT_SIZE, GUI_FONT_SIZE);
	 }
}




////////////////////////////////////////////////////////////////////////////////////////////////////////////



void ssd1306_init(SSD1306_t * dev, int width, int height)
{
	if (dev->_address == SPIAddress) {
		spi_init(dev, width, height);
	} else {
		//i2c_init(dev, width, height);
	}
}

void ssd1306_display_text(SSD1306_t * dev, int page, char * text, int text_len, bool invert)
{
	if (page >= dev->_pages) return;
	int _text_len = text_len;
	if (_text_len > 16) _text_len = 16;

	uint8_t seg = 0;
	uint8_t image[8];
	for (uint8_t i = 0; i < _text_len; i++) {
		memcpy(image, font8x8_basic_tr[(uint8_t)text[i]], 8);
		if (invert) ssd1306_invert(image, 8);
		if (dev->_flip) ssd1306_flip(image, 8);
		if (dev->_address == SPIAddress) {
			spi_display_image(dev, page, seg, image, 8);
		} else {
			//i2c_display_image(dev, page, seg, image, 8);
		}
		seg = seg + 8;
	}
}

void ssd1306_display_image(SSD1306_t * dev, int page, int seg, uint8_t * images, int width)
{
	if (dev->_address == SPIAddress) {
		spi_display_image(dev, page, seg, images, width);
	} else {
		//i2c_display_image(dev, page, seg, images, width);
	}
}

void ssd1306_clear_screen(SSD1306_t * dev, bool invert)
{
    char space[16];
    memset(space, 0x20, sizeof(space));
    for (int page = 0; page < dev->_pages; page++) {
        ssd1306_display_text(dev, page, space, sizeof(space), invert);
    }
}

void ssd1306_clear_line(SSD1306_t * dev, int page, bool invert)
{
    char space[16];
    memset(space, 0x20, sizeof(space));
    ssd1306_display_text(dev, page, space, sizeof(space), invert);
}

void ssd1306_contrast(SSD1306_t * dev, int contrast)
{
	if (dev->_address == SPIAddress) {
		spi_contrast(dev, contrast);
	} else {
		//i2c_contrast(dev, contrast);
	}
}

void ssd1306_software_scroll(SSD1306_t * dev, int start, int end)
{
	ESP_LOGD(tag, "software_scroll start=%d end=%d _pages=%d", start, end, dev->_pages);
	if (start < 0 || end < 0) {
		dev->_scEnable = false;
	} else if (start >= dev->_pages || end >= dev->_pages) {
		dev->_scEnable = false;
	} else {
		dev->_scEnable = true;
		dev->_scStart = start;
		dev->_scEnd = end;
		dev->_scDirection = 1;
		if (start > end ) dev->_scDirection = -1;
		for (int i=0;i<dev->_pages;i++) {
			dev->_page[i]._valid = false;
			dev->_page[i]._segLen = 0;
		}
	}
}


void ssd1306_scroll_text(SSD1306_t * dev, char * text, int text_len, bool invert)
{
	ESP_LOGD(tag, "dev->_scEnable=%d", dev->_scEnable);
	if (dev->_scEnable == false) return;

	void (*func)(SSD1306_t * dev, int page, int seg, uint8_t * images, int width);
	if (dev->_address == SPIAddress) {
		func = spi_display_image;
	} else {
		//func = i2c_display_image;
	}

	int srcIndex = dev->_scEnd - dev->_scDirection;
	while(1) {
		int dstIndex = srcIndex + dev->_scDirection;
		ESP_LOGD(tag, "srcIndex=%d dstIndex=%d", srcIndex,dstIndex);
		dev->_page[dstIndex]._valid = dev->_page[srcIndex]._valid;
		dev->_page[dstIndex]._segLen = dev->_page[srcIndex]._segLen;
		for(int seg = 0; seg < dev->_width; seg++) {
			dev->_page[dstIndex]._segs[seg] = dev->_page[srcIndex]._segs[seg];
		}
		ESP_LOGD(tag, "_valid=%d", dev->_page[dstIndex]._valid);
		if (dev->_page[dstIndex]._valid) (*func)(dev, dstIndex, 0, dev->_page[dstIndex]._segs, dev->_page[srcIndex]._segLen);
		if (srcIndex == dev->_scStart) break;
		srcIndex = srcIndex - dev->_scDirection;
	}
	
	int _text_len = text_len;
	if (_text_len > 16) _text_len = 16;
	
	uint8_t seg = 0;
	uint8_t image[8];
	for (uint8_t i = 0; i < _text_len; i++) {
		memcpy(image, font8x8_basic_tr[(uint8_t)text[i]], 8);
		if (invert) ssd1306_invert(image, 8);
		if (dev->_flip) ssd1306_flip(image, 8);
		(*func)(dev, srcIndex, seg, image, 8);
		for(int j=0;j<8;j++) dev->_page[srcIndex]._segs[seg+j] = image[j];
		seg = seg + 8;
	}
	dev->_page[srcIndex]._valid = true;
	dev->_page[srcIndex]._segLen = seg;
}

void ssd1306_scroll_clear(SSD1306_t * dev)
{
	ESP_LOGD(tag, "dev->_scEnable=%d", dev->_scEnable);
	if (dev->_scEnable == false) return;

	int srcIndex = dev->_scEnd - dev->_scDirection;
	while(1) {
		int dstIndex = srcIndex + dev->_scDirection;
		ESP_LOGD(tag, "srcIndex=%d dstIndex=%d", srcIndex,dstIndex);
		ssd1306_clear_line(dev, dstIndex, false);
		dev->_page[dstIndex]._valid = false;
		if (dstIndex == dev->_scStart) break;
		srcIndex = srcIndex - dev->_scDirection;
	}
}


void ssd1306_hardware_scroll(SSD1306_t * dev, ssd1306_scroll_type_t scroll)
{
	if (dev->_address == SPIAddress) {
		spi_hardware_scroll(dev, scroll);
	} else {
		//i2c_hardware_scroll(dev, scroll);
	}
}

void ssd1306_invert(uint8_t *buf, size_t blen)
{
	uint8_t wk;
	for(int i=0; i<blen; i++){
		wk = buf[i];
		buf[i] = ~wk;
	}
}

// Flip upside down
void ssd1306_flip(uint8_t *buf, size_t blen)
{
	for(int i=0; i<blen; i++){
		buf[i] = ssd1306_rotate(buf[i]);
	}
}

// Rotate 8-bit data
// 0x12-->0x48
uint8_t ssd1306_rotate(uint8_t ch1) {
	uint8_t ch2 = 0;
	for (int j=0;j<8;j++) {
		ch2 = (ch2 << 1) + (ch1 & 0x01);
		ch1 = ch1 >> 1;
	}
	return ch2;
}


void ssd1306_fadeout(SSD1306_t * dev)
{
	void (*func)(SSD1306_t * dev, int page, int seg, uint8_t * images, int width);
	if (dev->_address == SPIAddress) {
		func = spi_display_image;
	} else {
		//func = i2c_display_image;
	}

	uint8_t image[1];
	for(int page=0; page<dev->_pages; page++) {
		image[0] = 0xFF;
		for(int line=0; line<8; line++) {
			if (dev->_flip) {
				image[0] = image[0] >> 1;
			} else {
				image[0] = image[0] << 1;
			}
			for(int seg=0; seg<128; seg++) {
				(*func)(dev, page, seg, image, 1);
			}
		}
	}
}

void ssd1306_dump(SSD1306_t dev)
{
	printf("_address=%x\n",dev._address);
	printf("_width=%x\n",dev._width);
	printf("_height=%x\n",dev._height);
	printf("_pages=%x\n",dev._pages);
}
//////////////////////////////////////////////////////////////////////////////
void spi_master_init(SSD1306_t * dev, int16_t GPIO_MOSI, int16_t GPIO_SCLK, int16_t GPIO_CS, int16_t GPIO_DC, int16_t GPIO_RESET)
{
	esp_err_t ret;

	gpio_pad_select_gpio( GPIO_CS );
	gpio_set_direction( GPIO_CS, GPIO_MODE_OUTPUT );
	gpio_set_level( GPIO_CS, 0 );

	gpio_pad_select_gpio( GPIO_DC );
	gpio_set_direction( GPIO_DC, GPIO_MODE_OUTPUT );
	gpio_set_level( GPIO_DC, 0 );

	if ( GPIO_RESET >= 0 ) {
		gpio_pad_select_gpio( GPIO_RESET );
		gpio_set_direction( GPIO_RESET, GPIO_MODE_OUTPUT );
		gpio_set_level( GPIO_RESET, 0 );
		vTaskDelay( pdMS_TO_TICKS( 100 ) );
		gpio_set_level( GPIO_RESET, 1 );
	}

	spi_bus_config_t spi_bus_config = {
		.mosi_io_num = GPIO_MOSI,
		.miso_io_num = -1,
		.sclk_io_num = GPIO_SCLK,
		.quadwp_io_num = -1,
		.quadhd_io_num = -1,
		.max_transfer_sz = 0,
		.flags = 0
	};

	ret = spi_bus_initialize( LCD_HOST, &spi_bus_config, SPI_DMA_CH_AUTO );
	ESP_LOGI(tag, "spi_bus_initialize=%d",ret);
	assert(ret==ESP_OK);

	spi_device_interface_config_t devcfg;
	memset( &devcfg, 0, sizeof( spi_device_interface_config_t ) );
	devcfg.clock_speed_hz = SPI_Frequency;
	devcfg.spics_io_num = GPIO_CS;
	devcfg.queue_size = 1;

	spi_device_handle_t handle;
	ret = spi_bus_add_device( LCD_HOST, &devcfg, &handle);
	ESP_LOGI(tag, "spi_bus_add_device=%d",ret);
	assert(ret==ESP_OK);
	dev->_dc = GPIO_DC;
	dev->_SPIHandle = handle;
	dev->_address = SPIAddress;
	dev->_flip = false;
}


bool spi_master_write_byte(spi_device_handle_t SPIHandle, const uint8_t* Data, size_t DataLength )
{
	spi_transaction_t SPITransaction;

	if ( DataLength > 0 ) {
		memset( &SPITransaction, 0, sizeof( spi_transaction_t ) );
		SPITransaction.length = DataLength * 8;
		SPITransaction.tx_buffer = Data;
		spi_device_transmit( SPIHandle, &SPITransaction );
	}

	return true;
}

bool spi_master_write_command(SSD1306_t * dev, uint8_t Command )
{
	static uint8_t CommandByte = 0;
	CommandByte = Command;
	gpio_set_level( dev->_dc, SPI_Command_Mode );
	return spi_master_write_byte( dev->_SPIHandle, &CommandByte, 1 );
}

bool spi_master_write_data(SSD1306_t * dev, const uint8_t* Data, size_t DataLength )
{
	gpio_set_level( dev->_dc, SPI_Data_Mode );
	return spi_master_write_byte( dev->_SPIHandle, Data, DataLength );
}


void spi_init(SSD1306_t * dev, int width, int height)
{
	dev->_width = width;
	dev->_height = height;
	dev->_pages = 8;
	if (dev->_height == 32) dev->_pages = 4;

	spi_master_write_command(dev, OLED_CMD_DISPLAY_OFF);			// AE
	spi_master_write_command(dev, OLED_CMD_SET_MUX_RATIO);			// A8
	if (dev->_height == 64) spi_master_write_command(dev, 0x3F);
	if (dev->_height == 32) spi_master_write_command(dev, 0x1F);
	spi_master_write_command(dev, OLED_CMD_SET_DISPLAY_OFFSET);		// D3
	spi_master_write_command(dev, 0x00);
	spi_master_write_command(dev, OLED_CONTROL_BYTE_DATA_STREAM);	// 40
	if (dev->_flip) {
		spi_master_write_command(dev, OLED_CMD_SET_SEGMENT_REMAP_0);	// A0
	} else {
		spi_master_write_command(dev, OLED_CMD_SET_SEGMENT_REMAP_1);	// A1
	}
	//spi_master_write_command(dev, OLED_CMD_SET_SEGMENT_REMAP);		// A1
	spi_master_write_command(dev, OLED_CMD_SET_COM_SCAN_MODE);		// C8
	spi_master_write_command(dev, OLED_CMD_SET_DISPLAY_CLK_DIV);	// D5
	spi_master_write_command(dev, 0x80);
	spi_master_write_command(dev, OLED_CMD_SET_COM_PIN_MAP);		// DA
	if (dev->_height == 64) spi_master_write_command(dev, 0x12);
	if (dev->_height == 32) spi_master_write_command(dev, 0x02);
	spi_master_write_command(dev, OLED_CMD_SET_CONTRAST);			// 81
	spi_master_write_command(dev, 0xFF);
	spi_master_write_command(dev, OLED_CMD_DISPLAY_RAM);			// A4
	spi_master_write_command(dev, OLED_CMD_SET_VCOMH_DESELCT);		// DB
	spi_master_write_command(dev, 0x40);
	spi_master_write_command(dev, OLED_CMD_SET_MEMORY_ADDR_MODE);	// 20
	//spi_master_write_command(dev, OLED_CMD_SET_HORI_ADDR_MODE);	// 00
	spi_master_write_command(dev, OLED_CMD_SET_PAGE_ADDR_MODE);		// 02
	// Set Lower Column Start Address for Page Addressing Mode
	spi_master_write_command(dev, 0x00);
	// Set Higher Column Start Address for Page Addressing Mode
	spi_master_write_command(dev, 0x10);
	spi_master_write_command(dev, OLED_CMD_SET_CHARGE_PUMP);		// 8D
	spi_master_write_command(dev, 0x14);
	spi_master_write_command(dev, OLED_CMD_DEACTIVE_SCROLL);		// 2E
	spi_master_write_command(dev, OLED_CMD_DISPLAY_NORMAL);			// A6
	spi_master_write_command(dev, OLED_CMD_DISPLAY_ON);				// AF
}


void spi_display_image(SSD1306_t * dev, int page, int seg, uint8_t * images, int  width)
{
	if (page >= dev->_pages) return;
	if (seg >= dev->_width) return;

	int _seg = seg + CONFIG_OFFSETX;
	uint8_t columLow = _seg & 0x0F;
	uint8_t columHigh = (_seg >> 4) & 0x0F;

	int _page = page;
	if (dev->_flip) {
		_page = (dev->_pages - page) - 1;
	}

	// Set Lower Column Start Address for Page Addressing Mode
	spi_master_write_command(dev, (0x00 + columLow));
	// Set Higher Column Start Address for Page Addressing Mode
	spi_master_write_command(dev, (0x10 + columHigh));
	// Set Page Start Address for Page Addressing Mode
	spi_master_write_command(dev, 0xB0 | _page);

	spi_master_write_data(dev, images, width);

}

void spi_contrast(SSD1306_t * dev, int contrast) {
	int _contrast = contrast;
	if (contrast < 0x0) _contrast = 0;
	if (contrast > 0xFF) _contrast = 0xFF;

	spi_master_write_command(dev, OLED_CMD_SET_CONTRAST);			// 81
	spi_master_write_command(dev, _contrast);
}

void spi_hardware_scroll(SSD1306_t * dev, ssd1306_scroll_type_t scroll)
{

	if (scroll == SCROLL_RIGHT) {
		spi_master_write_command(dev, OLED_CMD_HORIZONTAL_RIGHT);	// 26
		spi_master_write_command(dev, 0x00); // Dummy byte
		spi_master_write_command(dev, 0x00); // Define start page address
		spi_master_write_command(dev, 0x07); // Frame frequency
		spi_master_write_command(dev, 0x07); // Define end page address
		spi_master_write_command(dev, 0x00); //
		spi_master_write_command(dev, 0xFF); //
		spi_master_write_command(dev, OLED_CMD_ACTIVE_SCROLL);		// 2F
	} 

	if (scroll == SCROLL_LEFT) {
		spi_master_write_command(dev, OLED_CMD_HORIZONTAL_LEFT);	// 27
		spi_master_write_command(dev, 0x00); // Dummy byte
		spi_master_write_command(dev, 0x00); // Define start page address
		spi_master_write_command(dev, 0x07); // Frame frequency
		spi_master_write_command(dev, 0x07); // Define end page address
		spi_master_write_command(dev, 0x00); //
		spi_master_write_command(dev, 0xFF); //
		spi_master_write_command(dev, OLED_CMD_ACTIVE_SCROLL);		// 2F
	} 

	if (scroll == SCROLL_DOWN) {
		spi_master_write_command(dev, OLED_CMD_CONTINUOUS_SCROLL);	// 29
		spi_master_write_command(dev, 0x00); // Dummy byte
		spi_master_write_command(dev, 0x00); // Define start page address
		spi_master_write_command(dev, 0x07); // Frame frequency
		//spi_master_write_command(dev, 0x01); // Define end page address
		spi_master_write_command(dev, 0x00); // Define end page address
		spi_master_write_command(dev, 0x3F); // Vertical scrolling offset

		spi_master_write_command(dev, OLED_CMD_VERTICAL);			// A3
		spi_master_write_command(dev, 0x00);
		if (dev->_height == 64)
			spi_master_write_command(dev, 0x40);
		if (dev->_height == 32)
			spi_master_write_command(dev, 0x20);
		spi_master_write_command(dev, OLED_CMD_ACTIVE_SCROLL);		// 2F
	}

	if (scroll == SCROLL_UP) {
		spi_master_write_command(dev, OLED_CMD_CONTINUOUS_SCROLL);	// 29
		spi_master_write_command(dev, 0x00); // Dummy byte
		spi_master_write_command(dev, 0x00); // Define start page address
		spi_master_write_command(dev, 0x07); // Frame frequency
		//spi_master_write_command(dev, 0x01); // Define end page address
		spi_master_write_command(dev, 0x00); // Define end page address
		spi_master_write_command(dev, 0x01); // Vertical scrolling offset

		spi_master_write_command(dev, OLED_CMD_VERTICAL);			// A3
		spi_master_write_command(dev, 0x00);
		if (dev->_height == 64)
			spi_master_write_command(dev, 0x40);
		if (dev->_height == 32)
			spi_master_write_command(dev, 0x20);
		spi_master_write_command(dev, OLED_CMD_ACTIVE_SCROLL);		// 2F
	}

	if (scroll == SCROLL_STOP) {
		spi_master_write_command(dev, OLED_CMD_DEACTIVE_SCROLL);	// 2E
	}
}




////////////////////////////////////////////////////////////////////////////////
void bsp_ssd1306_init(void)
{
    
	int center, top, bottom;
	char lineChar[20];

    ESP_LOGI(tag, "INTERFACE is SPI");
	ESP_LOGI(tag, "CONFIG_MOSI_GPIO=%d",CONFIG_MOSI_GPIO);
	ESP_LOGI(tag, "CONFIG_SCLK_GPIO=%d",CONFIG_SCLK_GPIO);
	ESP_LOGI(tag, "CONFIG_CS_GPIO=%d",CONFIG_CS_GPIO);
	ESP_LOGI(tag, "CONFIG_DC_GPIO=%d",CONFIG_DC_GPIO);
	ESP_LOGI(tag, "CONFIG_RESET_GPIO=%d",CONFIG_RESET_GPIO);
	spi_master_init(&dev, CONFIG_MOSI_GPIO, CONFIG_SCLK_GPIO, CONFIG_CS_GPIO, CONFIG_DC_GPIO, CONFIG_RESET_GPIO);


    dev._flip = true;
	ESP_LOGW(tag, "Flip upside down");

    ESP_LOGI(tag, "Panel is 128x64");
	ssd1306_init(&dev, 128, 64);


    ssd1306_clear_screen(&dev, false);
	ssd1306_contrast(&dev, 0xff);


			

	///while(1)
	///{

			


	///}



	/*
    top = 2;
	center = 3;
	bottom = 8;
	ssd1306_display_text(&dev, 0, "SSD1306 128x64", 14, false);
	ssd1306_display_text(&dev, 1, "ABCDEFGHIJKLMNOP", 16, false);
	ssd1306_display_text(&dev, 2, "abcdefghijklmnop",16, false);
	ssd1306_display_text(&dev, 3, "Hello World!!", 13, false);
	ssd1306_clear_line(&dev, 4, true);
	ssd1306_clear_line(&dev, 5, true);
	ssd1306_clear_line(&dev, 6, true);
	ssd1306_clear_line(&dev, 7, true);
	ssd1306_display_text(&dev, 4, "SSD1306 128x64", 14, true);
	ssd1306_display_text(&dev, 5, "ABCDEFGHIJKLMNOP", 16, true);
	ssd1306_display_text(&dev, 6, "abcdefghijklmnop",16, true);
	ssd1306_display_text(&dev, 7, "Hello World!!", 13, true);
	
    vTaskDelay(3000 / portTICK_PERIOD_MS);
	
	*/
    ///ssd1306_clear_screen(&dev, false);

	//sprintf(&lineChar[0], "%2d"   "    %3d", App.Tosop_Is_CONNECT_FLAG,App.Tospo_Edu_Rssi);
   // ssd1306_display_text(&dev, 2, lineChar, strlen(lineChar), false);

	//ssd1306_display_text(&dev, 5, "chan  col  row", 16, false);
	//sprintf(&lineChar[0], " %03d <%03d> %03d", App.Tosop_Edu_Channel,App.Tosop_Edu_column,App.Tosop_Edu_Row);
	//ssd1306_display_text(&dev, 6, lineChar, strlen(lineChar), false);
    //while(1)
    {
        /*
        sprintf(&lineChar[0], "Channel:%03d", App.Tosop_Edu_Channel);
        ssd1306_display_text(&dev, 2, lineChar, strlen(lineChar), false);


        sprintf(&lineChar[0], "Column:%03d", App.Tosop_Edu_column);
        ssd1306_display_text(&dev, 4, lineChar, strlen(lineChar), false);


        sprintf(&lineChar[0], "Row:%03d", App.Tosop_Edu_Row);
        ssd1306_display_text(&dev, 6, lineChar, strlen(lineChar), false);
		
        vTaskDelay(1000 / portTICK_PERIOD_MS);
		*/
    }


	/*
    while(1){

    ssd1306_clear_screen(&dev, true);

    // Display Count Down
	uint8_t image[24];
	memset(image, 0, sizeof(image));
	ssd1306_display_image(&dev, top, (6*8-1), image, sizeof(image));
	ssd1306_display_image(&dev, top+1, (6*8-1), image, sizeof(image));
	ssd1306_display_image(&dev, top+2, (6*8-1), image, sizeof(image));
	for(int font=0x39;font>0x30;font--) {
		memset(image, 0, sizeof(image));
		ssd1306_display_image(&dev, top+1, (7*8-1), image, 8);
		memcpy(image, font8x8_basic_tr[font], 8);
		if (dev._flip) ssd1306_flip(image, 8);
		ssd1306_display_image(&dev, top+1, (7*8-1), image, 8);
		vTaskDelay(1000 / portTICK_PERIOD_MS);
	}
	
	// Scroll Up
	ssd1306_clear_screen(&dev, false);
	ssd1306_contrast(&dev, 0xff);
	ssd1306_display_text(&dev, 0, "---Scroll  UP---", 16, true);
	//ssd1306_software_scroll(&dev, 7, 1);
	ssd1306_software_scroll(&dev, (dev._pages - 1), 1);
	for (int line=0;line<bottom+10;line++) {
		lineChar[0] = 0x01;
		sprintf(&lineChar[1], " Line %02d", line);
		ssd1306_scroll_text(&dev, lineChar, strlen(lineChar), false);
		vTaskDelay(500 / portTICK_PERIOD_MS);
	}
	vTaskDelay(3000 / portTICK_PERIOD_MS);
	
	// Scroll Down
	ssd1306_clear_screen(&dev, false);
	ssd1306_contrast(&dev, 0xff);
	ssd1306_display_text(&dev, 0, "--Scroll  DOWN--", 16, true);
	//ssd1306_software_scroll(&dev, 1, 7);
	ssd1306_software_scroll(&dev, 1, (dev._pages - 1) );
	for (int line=0;line<bottom+10;line++) {
		lineChar[0] = 0x02;
		sprintf(&lineChar[1], " Line %02d", line);
		ssd1306_scroll_text(&dev, lineChar, strlen(lineChar), false);
		vTaskDelay(500 / portTICK_PERIOD_MS);
	}
	vTaskDelay(1000 / portTICK_PERIOD_MS);

	// Page Down
	ssd1306_clear_screen(&dev, false);
	ssd1306_contrast(&dev, 0xff);
	ssd1306_display_text(&dev, 0, "---Page	DOWN---", 16, true);
	ssd1306_software_scroll(&dev, 1, (dev._pages-1) );
	for (int line=0;line<bottom+10;line++) {
		//if ( (line % 7) == 0) ssd1306_scroll_clear(&dev);
		if ( (line % (dev._pages-1)) == 0) ssd1306_scroll_clear(&dev);
		lineChar[0] = 0x02;
		sprintf(&lineChar[1], " Line %02d", line);
		ssd1306_scroll_text(&dev, lineChar, strlen(lineChar), false);
		vTaskDelay(500 / portTICK_PERIOD_MS);
	}
	vTaskDelay(1000 / portTICK_PERIOD_MS);

	// Horizontal Scroll
	ssd1306_clear_screen(&dev, false);
	ssd1306_contrast(&dev, 0xff);
	ssd1306_display_text(&dev, center, "Horizontal", 10, false);
	ssd1306_hardware_scroll(&dev, SCROLL_RIGHT);
	vTaskDelay(3000 / portTICK_PERIOD_MS);
	ssd1306_hardware_scroll(&dev, SCROLL_LEFT);
	vTaskDelay(3000 / portTICK_PERIOD_MS);
	ssd1306_hardware_scroll(&dev, SCROLL_STOP);
	
	// Vertical Scroll
	ssd1306_clear_screen(&dev, false);
	ssd1306_contrast(&dev, 0xff);
	ssd1306_display_text(&dev, center, "Vertical", 8, false);
	ssd1306_hardware_scroll(&dev, SCROLL_DOWN);
	vTaskDelay(3000 / portTICK_PERIOD_MS);
	ssd1306_hardware_scroll(&dev, SCROLL_UP);
	vTaskDelay(3000 / portTICK_PERIOD_MS);
	ssd1306_hardware_scroll(&dev, SCROLL_STOP);
	
	// Invert
	ssd1306_clear_screen(&dev, true);
	ssd1306_contrast(&dev, 0xff);
	ssd1306_display_text(&dev, center, "  Good Bye!!", 12, true);
	vTaskDelay(2000 / portTICK_PERIOD_MS);

    }
	// Fade Out
	ssd1306_fadeout(&dev);

	*/
} 